package com.apobates.forum.toro.tuple;

import com.apobates.forum.toro.core.BeanParser;
import com.apobates.forum.toro.core.Corner;
import com.apobates.forum.toro.core.Express;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
 * 单一左对象Pair映射语句
 * @param <L> 左对象类型
 * @since 20220827
 * @author xiaofanku@live.cn
 */
public class PairMapperStatements<L> {
    private final static BeanParser<PairMapperStatements.Argument> parser;
    static {
        // R(rightAttr:rightAttrType)
        Express exp = Express.getInstance()
                .word("rightAttr")
                .corner(Corner.sequence(0).edge(":").build())
                .word("rightAttrType")
                .corner(Corner.sequence(1).edge(")").build());
        // 从表达式到实例
        parser = exp.build(PairMapperStatements.Argument.class);
    }

    /**
     * 设置连接右对象的左对象属性名称
     * 通过Argument构造者设置关联右对象的属性。注意：不要与expr混用
     *
     * @param rightAttr 连接右对象的左对象属性名称
     * @return 右对象表达式语句构建器
     */
    public Argument right(String rightAttr) {
        return new Argument().right(rightAttr);
    }

    /**
     * 设置参数语句表达式描述
     * 通过描述字符串设置右对象的连接属性。注意：不要与attr混用
     * 格式: R(rightAttr:rightAttrType)
     * @param exprDescribe 查询参数表达式描述
     * @return
     */
    public Argument expr(String exprDescribe){
        // R(rightAttr:rightAttrType)
        Map<String,Object> argMap = parser.toMap(exprDescribe, "R(");
        return new Argument()
                .right(argMap.get("rightAttr").toString())
                .rightType(argMap.get("rightAttrType").toString());
    }

    /**
     * ASF Lang3 Pair连接参数
     */
    public class Argument{
        /**
         * 左对象哪个属性可以用来获取右对象
         */
        private String rightAttr;
        /**
         * 右对象连接属性的类型
         */
        private String rightAttrType;

        private Argument() {

        }

        /**
         * 设置连接R的属性名称
         * @param rightAttr 右对象关联的属性名称
         * @return
         */
        public Argument right(String rightAttr){
            this.rightAttr = rightAttr;
            return this;
        }

        /**
         * 设置连接R的属性类型
         * @param rightAttrType 右对象关联的属性类型
         * @return
         */
        public Argument rightType(String rightAttrType) {
            this.rightAttrType = rightAttrType;
            return this;
        }

        /**
         * 左对象与右对象是一对一
         * @param leftIns
         * @return
         */
        public PairMapperExecutor<L> by(L leftIns){
            return new PairMapperExecutor(()->leftIns, this.buildArguments());
        }

        /**
         * 左对象与右对象是一对一
         * @param leftInsSup
         * @return
         */
        public PairMapperExecutor<L> supply(Supplier<L> leftInsSup){
            return new PairMapperExecutor(leftInsSup, this.buildArguments());
        }

        /**
         * 左对象与右对象是一对多
         * @param leftIns
         * @return
         */
        public PairAnyMapperExecutor<L> byAny(L leftIns){
            return new PairAnyMapperExecutor(()->leftIns, this.buildArguments());
        }

        /**
         * 左对象与右对象是一对多
         * @param leftInsSup
         * @return
         */
        public PairAnyMapperExecutor<L> supplyAny(Supplier<L> leftInsSup){
            return new PairAnyMapperExecutor(leftInsSup, this.buildArguments());
        }

        private Map<String,String> buildArguments(){
            Map<String, String> arguments = new HashMap<>();
            arguments.put("rightAttr", this.rightAttr);
            arguments.put("rightAttrType", this.rightAttrType);
            return arguments;
        }
    }
}
